package com.ruoyi.web.controller.tool.accesslimit;

import com.ruoyi.common.core.redis.RedisCache;
import com.ruoyi.common.exception.ServiceException;
import com.ruoyi.common.utils.ServletUtils;
import com.ruoyi.common.utils.ip.IpUtils;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Before;
import org.aspectj.lang.reflect.MethodSignature;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.http.HttpStatus;
import org.springframework.stereotype.Component;

import javax.servlet.http.HttpServletRequest;
import java.util.concurrent.TimeUnit;

@Aspect
@Component
public class MyRateLimiterAspect {
    @Autowired
    private RedisCache redisCache;

    @Before("@annotation(rateLimiter)")
    public void doBefore(JoinPoint point, RateLimiter rateLimiter) {
        String key = buildKey(point, rateLimiter);

        // 使用RedisCache原子操作
        Long count = redisCache.incr(key, 1);
        if (count != null && count == 1) {
            redisCache.expire(key, rateLimiter.time(), TimeUnit.SECONDS);
        }

        if (count != null && count > rateLimiter.count()) {
            if (rateLimiter.name().equals("getCode")){
                throw new ServiceException("获取验证码过于频繁，请稍后再试", HttpStatus.TOO_MANY_REQUESTS.value());
            }
            throw new ServiceException("访问过于频繁，请稍后再试", HttpStatus.TOO_MANY_REQUESTS.value());
        }
    }

    private String buildKey(JoinPoint point, RateLimiter rateLimiter) {
        HttpServletRequest request = ServletUtils.getRequest();
        String ip = IpUtils.getIpAddr(request);
        MethodSignature signature = (MethodSignature) point.getSignature();
        return String.format("rate_limit:%s:%s:%s",
                rateLimiter.type().name(),
                ip,
                signature.getMethod().getDeclaringClass().getName() + "." + signature.getName());
    }
}